#include "model.h"




void Model::loadModel(string path)
{
    // 检查源文件是否存在
    if (!QFile::exists(path.c_str())) {
        qDebug() << "Source file does not exist:" << path.c_str();
        return;
    }
qDebug() << path.c_str() << " " << QFileInfo(path.c_str()).fileName();
    // 复制文件到当前目录
    if (QFile::copy(path.c_str(), QFileInfo(path.c_str()).fileName())) {
        //qDebug() << "File copied successfully to:" << targetPath;
    } else {
        //qDebug() << "Failed to copy file to:" << targetPath;
    }
    path = QFileInfo(path.c_str()).fileName().toStdString();


    tinygltf::Model model;
    tinygltf::TinyGLTF loader;
    std::string err;
    std::string warn;

    bool ret = loader.LoadBinaryFromFile(&model, &err, &warn, path);

    if (!warn.empty()) qWarning() << warn.c_str();
    if (!err.empty()) qCritical() << err.c_str();
    if (!ret) {
        qCritical() << " load error!";
        throw std::runtime_error("Failed to load glTF model!");
    }

    qDebug() << "meshes.size: " << model.meshes.size();



    /** @note Assume one Node just one Mesh */
    int nodeIndex = 0;
    for (const auto& node : model.nodes)
    {
        // !Assume one Node just one Mesh
        const auto& mesh = model.meshes[node.mesh];// #Mesh
        s_meshNames.insert(nodeIndex, QString::fromStdString(mesh.name));

        for (const auto& primitive : mesh.primitives)
        {
            // #Primitive
            if (primitive.attributes.find("POSITION") != primitive.attributes.end())
            {// #Vertex
                const auto& positionAccessor = model.accessors[primitive.attributes.at("POSITION")];
                const auto& positionBufferView = model.bufferViews[positionAccessor.bufferView];
                const auto& positionBuffer = model.buffers[positionBufferView.buffer];
#if SUPPORT_VEC
                //vector<Vertex> _vertices;
                QVector<QVector3D> _vertices;
#else
                QVector<QVector3D> _vertices;
#endif
                const auto* vertices = reinterpret_cast<const float*>(&positionBuffer.data[positionBufferView.byteOffset + positionAccessor.byteOffset]);
                for (size_t i = 0; i < positionAccessor.count; ++i)
                {
#if SUPPORT_VEC
                    QVector3D p = QVector3D(vertices[i * 3], vertices[i * 3 + 1], vertices[i * 3 + 2]);
                    //Vertex p;
                    //p.Position = QVector3D(vertices[i * 3], vertices[i * 3 + 1], vertices[i * 3 + 2]);
#else
                    const auto& p = QVector3D(vertices[i * 3], vertices[i * 3 + 1], vertices[i * 3 + 2]);
#endif
                    _vertices.push_back(p);
                }
                s_vertices.insert(nodeIndex, _vertices);
            }

            if (primitive.attributes.find("NORMAL") != primitive.attributes.end())
            {
                // #Normal
                const auto& normalAccessor = model.accessors[primitive.attributes.at("NORMAL")];
                const auto& normalBufferView = model.bufferViews[normalAccessor.bufferView];
                const auto& normalBuffer = model.buffers[normalBufferView.buffer];

                QVector<QVector3D> _normals;
                const float* normals = reinterpret_cast<const float*>(&normalBuffer.data[normalBufferView.byteOffset + normalAccessor.byteOffset]);
                for (size_t i = 0; i < normalAccessor.count; ++i)
                    _normals << QVector3D(normals[i * 3], normals[i * 3 + 1], normals[i * 3 + 2]);
                s_normals.insert(nodeIndex, _normals);
            }

            if (primitive.attributes.find("TEXCOORD_0") != primitive.attributes.end())
            {
                // #Texcoord
                const auto& texcoordAccessor = model.accessors[primitive.attributes.at("TEXCOORD_0")];
                const auto& texcoordBufferView = model.bufferViews[texcoordAccessor.bufferView];
                const auto& texcoordBuffer = model.buffers[texcoordBufferView.buffer];

                QVector<QVector2D> _texcoords;
                const float* texcoords = reinterpret_cast<const float*>(&texcoordBuffer.data[texcoordBufferView.byteOffset + texcoordAccessor.byteOffset]);
                for (size_t i = 0; i < texcoordAccessor.count; ++i)
                    _texcoords << QVector2D(texcoords[i * 2], texcoords[i * 2 + 1]);
                s_texcoords.insert(nodeIndex, _texcoords);
                //qDebug() << s_texcoords << nodeIndex;
            }

            if (primitive.indices >= 0)
            {
                // #Index
                const auto& indexAccessor = model.accessors[primitive.indices];
                const auto& indexBufferView = model.bufferViews[indexAccessor.bufferView];
                const auto& indexBuffer = model.buffers[indexBufferView.buffer];
#if SUPPORT_VEC
                QVector<unsigned int> _indices;
#else
                QVector<unsigned int> _indices;
#endif
                if (indexAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT)
                {
                    const unsigned short* indices = reinterpret_cast<const unsigned short*>(&indexBuffer.data[indexBufferView.byteOffset + indexAccessor.byteOffset]);
                    for (size_t i = 0; i < indexAccessor.count; ++i)
                        _indices.push_back(indices[i]);
                } else if (indexAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT)
                {
                    const unsigned int* indices = reinterpret_cast<const unsigned int*>(&indexBuffer.data[indexBufferView.byteOffset + indexAccessor.byteOffset]);
                    for (size_t i = 0; i < indexAccessor.count; ++i)
                        _indices.push_back(indices[i]);
                }
                s_indices.insert(nodeIndex, _indices);
            }

            if (primitive.material >= 0 && primitive.material < model.materials.size())
            {
#if 1
                Material _material;

                const auto& material = model.materials[primitive.material];
                if (material.pbrMetallicRoughness.baseColorFactor.size() == 4)
                {// #Material (if size is not 4, it means bad datas in glTF file)
                    float r = material.pbrMetallicRoughness.baseColorFactor[0];
                    float g = material.pbrMetallicRoughness.baseColorFactor[1];
                    float b = material.pbrMetallicRoughness.baseColorFactor[2];
                    float a = material.pbrMetallicRoughness.baseColorFactor[3];
                    _material.setBaseColor(QColor::fromRgbF(r, g, b, a));
                }

                if (material.pbrMetallicRoughness.metallicFactor > 0.0f)// [0, 1]
                    _material.setMetallic(material.pbrMetallicRoughness.metallicFactor);
                else
                    _material.setMetallic(0);// no metallic

                if (material.pbrMetallicRoughness.roughnessFactor > 0.0f)// [0, 1]
                    _material.setRoughness(material.pbrMetallicRoughness.roughnessFactor);
                else
                    _material.setRoughness(0);// no roughness

                s_materials.insert(nodeIndex, _material);
#endif
            }
            else
                qInfo() << "read glTF no Material: define Default. # modelType";
        }

        ++nodeIndex;
    }// end for #Node
}

void Model::Draw(Shader &shader)
{
    for(unsigned int i = 0; i < s_meshNames.size(); i++)
    {
        //qDebug() << i << " " << s_vertices[i].size() << " " << s_indices[i].size();
#if SUPPORT_VEC
        Mesh mesh(m_glFuns, s_vertices[i], s_indices[i],vector<Texture>{});
#else
        Mesh mesh(m_glFuns, s_vertices[i], s_indices[i]);
#endif
        mesh.Draw(shader);
    }
}
